/*
 * Equivalence.java
 *
 * Copyright (C) 2008  Pei Wang
 *
 * This file is part of Open-NARS.
 *
 * Open-NARS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * Open-NARS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Open-NARS.  If not, see <http://www.gnu.org/licenses/>.
 */
package nars.language;

import nars.inference.TemporalRules;
import nars.io.Symbols.NativeOperator;
import nars.storage.Memory;

/**
 * A Statement about an Equivalence relation.
 */
public class Equivalence extends Statement {

    private int temporalOrder = TemporalRules.ORDER_NONE;

    /**
     * Constructor with partial values, called by make
     *
     * @param components The component list of the term
     */
    private Equivalence(CharSequence name, Term[] components, int order) {
        super(name, components);
        temporalOrder = order;
    }

    /**
     * Constructor with full values, called by clone
     *
     * @param n The name of the term
     * @param components Component list
     * @param constant Whether the statement contains open variable
     * @param complexity Syntactic complexity of the compound
     */
    private Equivalence(CharSequence n, Term[] components, boolean constant, short complexity, int order) {
        super(n, components, constant, complexity);
        temporalOrder = order;
    }

    /**
     * Clone an object
     *
     * @return A new object
     */
    @Override
    public Equivalence clone() {
        return new Equivalence(name(), cloneTerms(), isConstant(), complexity, temporalOrder);
    }

    /**
     * Try to make a new compound from two term. Called by the inference
     * rules.
     *
     * @param subject The first component
     * @param predicate The second component
     * @param memory Reference to the memory
     * @return A compound generated or null
     */
    public static Equivalence make(Term subject, Term predicate, Memory memory) {  // to be extended to check if subject is Conjunction
        return make(subject, predicate, TemporalRules.ORDER_NONE, memory);
    }

    public static Equivalence make(Term subject, Term predicate, int temporalOrder, Memory memory) {  // to be extended to check if subject is Conjunction
        if (invalidStatement(subject, predicate)) {
            return null;
        }
        if ((subject instanceof Implication) || (subject instanceof Equivalence)
                || (predicate instanceof Implication) || (predicate instanceof Equivalence)) {
            return null;
        }
        if ((temporalOrder == TemporalRules.ORDER_BACKWARD)
                || ((subject.compareTo(predicate) > 0) && (temporalOrder != TemporalRules.ORDER_FORWARD))) {
            Term interm = subject;
            subject = predicate;
            predicate = interm;
        }
        NativeOperator copula;
        switch (temporalOrder) {
            case TemporalRules.ORDER_BACKWARD:
                temporalOrder = TemporalRules.ORDER_FORWARD;
                //TODO determine if this missing break is intended
            case TemporalRules.ORDER_FORWARD:
                copula = NativeOperator.EQUIVALENCE_AFTER;
                break;
            case TemporalRules.ORDER_CONCURRENT:
                copula = NativeOperator.EQUIVALENCE_WHEN;
                break;
            default:
                copula = NativeOperator.EQUIVALENCE;
        }
        CharSequence name = makeStatementName(subject, copula, predicate);
        Term t = memory.conceptTerm(name);
        if (t != null) {
            return (Equivalence) t;
        }
        return new Equivalence(name, termArray(subject, predicate), temporalOrder);
    }

    /**
     * Get the operator of the term.
     *
     * @return the operator of the term
     */
    @Override
    public NativeOperator operator() {
        switch (temporalOrder) {
            case TemporalRules.ORDER_FORWARD:
                return NativeOperator.EQUIVALENCE_AFTER;
            case TemporalRules.ORDER_CONCURRENT:
                return NativeOperator.EQUIVALENCE_WHEN;
        }
        return NativeOperator.EQUIVALENCE;
    }

    /**
     * Check if the compound is commutative.
     *
     * @return true for commutative
     */
    @Override
    public boolean isCommutative() {
        return (temporalOrder != TemporalRules.ORDER_FORWARD);
    }

    @Override
    public int getTemporalOrder() {
        return temporalOrder;
    }
}
